#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/timerfd.h>
#include <string.h>
#include <errno.h>
#include <sys/epoll.h>
#include <time.h>

#define TIMER_INTERVAL_SEC 3 // 定时器间隔（秒）
#define TIMER_INITIAL_DELAY_SEC 3 // 初始延迟（秒）

int main() {

    // 创建一个时钟文件描述符，CLOCK_REALTIME 表示使用实时时钟
    int timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
    if (timerfd == -1) {
        perror("timerfd_create");
        exit(EXIT_FAILURE);
    }

    // 设置定时器初始值和间隔时间
    struct itimerspec new_value;
    memset(&new_value, 0, sizeof(new_value));
    new_value.it_value.tv_sec = TIMER_INITIAL_DELAY_SEC; 
    new_value.it_value.tv_nsec = 0;  // 第一次超时时间
    new_value.it_interval.tv_nsec = 0;
    new_value.it_interval.tv_sec = TIMER_INTERVAL_SEC; // 每隔多少秒触发一次

    // 启动定时器
    if (timerfd_settime(timerfd, 0, &new_value, NULL) == -1) {
        perror("timerfd_settime");
        close(timerfd);
        exit(EXIT_FAILURE);
    }

    // 这里可以使用 epoll、select 或 poll 来等待定时器文件描述符上的事件
    // 为了简单起见，这里使用简单的 read 循环来等待定时器触发
    while (1)
    {
        uint64_t expirations; // 8字节的数据
        // 读取定时器文件描述符上的数据，数据表示定时器触发的次数
        ssize_t ret = read(timerfd, &expirations, sizeof(expirations));
        if (ret == -1)
        {
            perror("read");
            close(timerfd);
            exit(EXIT_FAILURE);
        }

        // 处理定时器触发事件
        printf("超时了，距离上一次超时了%ld次\n", expirations);

        // 为了避免无限循环，可以在这里添加退出条件
        // 例如，可以设置一个计数器，当达到某个值时退出循环
        // 在这个简单示例中，我们使用 break 来退出循环（仅用于演示）
        // 注意：在实际应用中，通常不会这样做，因为这样会失去定时器的意义
        // 这里只是为了演示如何读取和处理定时器事件
    }

    // 关闭定时器文件描述符
    close(timerfd);

    return 0;
}